;
;       Forbin LFO
;       ==========
;
;       (c) Copyright 2009 -- Cotopaxi Engineering
;
;------------------------------------------------------------------------------
;
        .equ     __30F2010,1
        .include "p30f2010.inc"
;
;------------------------------------------------------------------------------
;
;       configuration bits
;
        config __FOSC,CSW_FSCM_OFF & XT ; _PLL4    ; Turn off clock switching and
                                                ; fail-safe clock monitoring and
                                                ; use a crystal oscillator with
                                                ; the 4x PLL

        config __FWDT,WDT_OFF                   ; disable watchdog timer

        config __FBORPOR,PBOR_ON & BORV_45 & PWRT_16 & MCLR_EN
                                                ; brown-out reset voltage -> 4.5V
                                                ; power-up timer -> 16msecs
												; MCLR pin enabled

        config __FGS,CODE_PROT_OFF              ; code protection off for the
                                                ; general segment
;
;------------------------------------------------------------------------------
;
;       global declarations
;
        .global __reset             ; the label for the first line of code
        .global __T1Interrupt       ; declare Timer 1 ISR name global
        .global __SPI1Interrupt     ; interrupt entry from the SPI
;
;------------------------------------------------------------------------------
;
;		Hardware definitions
;
		.equ	DAC_LD_PIN,3		; RE3
		.equ	DAC_CS1_PIN,4		; RE4
		.equ	DAC_CS2_PIN,5		; RE5
		.equ	DAC_CLK_PIN,6		; RE8
;
;------------------------------------------------------------------------------
;
;		the various waveshapes available
;
		.equ	SINE_SHAPE,1	; sinewave
		.equ	TRI_SHAPE,2		; trianble wave
		.equ	RAMP_SHAPE,3	; ramp -- +ve going
		.equ	SAW_SHAPE,4		; sawtooth -- -ve going
		.equ	SQR_SHAPE,5		; square wave
		.equ	RND_SHAPE,6		; random
;
;------------------------------------------------------------------------------
;
;       	variable data storage
;
        	.section	.bss
;
;			these values are read from the ADC measurements from the front panel
;			and the connectors...
;
freq_val:	.space		2			; current frequency value
phase_val:	.space		2			; current phase value
shape_val:	.space		2			; wave shape value
neg_shape:	.space		2			; -ve waveshape control "type"
unity_shape: .space		2			; unity waveshape control "type"
pos_shape:	.space		2			; +ve waveshape control "type"
randval:	.space		4			; random number
pwm_val:	.space		2			; pulse width of the square wave
;
;			derived/working values based upon the above values!
;
angular_pos: .space		2			; current angular position for channel 0
;
;			the output buffer -- as a sanity check the lower bits denote the channel
;
			.align		32
outbuf: 	.space		32
;
;------------------------------------------------------------------------------
;
;       code starts here!
;
        .text                    
;
;------------------------------------------------------------------------------
;
;       SPI Interrupt Service Routine -- this is at the beginning to keep
;		all the jumps low numbers...
;
__SPI1Interrupt:
        bclr    IFS0,#SPI1IF        ; clear the SPI interrupt flag Status
		mov		SPI1BUF,W13 		; read the buffer to clear -- not used...
		goto	W14					; call the next state in the SPI outputting chain
;
SPIState1:
		bset	LATE,#DAC_CS2_PIN   ; all off before LDAC -- tLS > 40nS
		bclr	LATE,#DAC_LD_PIN	; drive LDAC low
		bset	LATE,#DAC_LD_PIN    ; LDAC high again now CS of 1 low
		mov		#handle(SPIState2),W14
		bclr	LATE,#DAC_CS1_PIN   ; select the 1st DAC
;
		mov		#0x0fff,W13			; constrain 0->4096
		and		W12,W13,W12
		lsr		W12,#5,W1			; work out the step into the table / 32
		sl		W1,#2,W1			; x number of bytes per entry
		mov		#psvoffset(stab),W2
		add		W2,W1,W1			; now index into the table
		and		W12,#0b11111,W0		; mask off the bottom 5 bits
		mul.ss	W0,[W1++],W2		; multiply by scaling value
		asr		W2,#5,W2			; scaling back to adjust for rounding
		add		W2,[W1],W0
;
		mov		#0xf000,W13
		ior		W13,W0,W13
		bclr	WREG13,#15
		mov		W13,SPI1BUF
        retfie
;
SPIState2:
		bset	LATE,#DAC_CS1_PIN   ; all off for a moment
		mov		#handle(SPIState3),W14
		bclr	LATE,#DAC_CS1_PIN   ; select the 1st DAC
;
		mov		#0xf000,W13
		ior		W13,W12,W13
		mov		W13,SPI1BUF
        retfie
;
SPIState3:
		bset	LATE,#DAC_CS1_PIN   ; all off for a moment
		mov		#handle(SPIState4),W14
		bclr	LATE,#DAC_CS2_PIN   ; select the 2nd DAC
;
		mov		#0x0fff,W11			; constrain 0->4096
		and		W11,W12,W13
 		sub		W11,W13,W13
		and		W11,W13,W13
		mov		#0xf000,W11
		ior		W11,W13,W13
		bclr	WREG13,#15
		mov		W13,SPI1BUF
        retfie
;
SPIState4:
		bset	LATE,#DAC_CS2_PIN   ; all off for a moment
		mov		#handle(SPIState1),W14
		bclr	LATE,#DAC_CS2_PIN   ; select the 2nd DAC
;
		mov		#1024,W1
		add		W1,W12,W1
		mov		#0x0fff,W13			; constrain 0->4096
		and		W1,W13,W1
		lsr		W1,#5,W1			; work out the step into the table / 32
		sl		W1,#2,W1			; x number of bytes per entry
		mov		#psvoffset(stab),W2
		add		W2,W1,W1			; now index into the table
		and		W12,#0b11111,W0		; mask off the bottom 5 bits
		mul.ss	W0,[W1++],W2		; multiply by scaling value
		asr		W2,#5,W2			; scaling back to adjust for rounding
		add		W2,[W1],W0
;
		mov		#0xf000,W13
		ior		W13,W0,W13
		mov		W13,SPI1BUF
		add		#1,W12
        retfie
;
;------------------------------------------------------------------------------
;
;		mainline starts from here
;
__reset:
        mov     #__SP_init,W15      ; setup stack pointer
        mov     #__SPLIM_init,W0    ; setup the stack overflow register as well
        mov     W0,SPLIM
        nop                         ; add NOP to follow SPLIM initialization
;
;		setup the hardware
;
;		port B -- the 6 analog inputs -- the 3 inputs for the wave selection and the CV
;
        mov     #0b000000,W0        ; setup port B pins into analog mode
        mov     W0,ADPCFG           
        mov     #0b111111,W0        ; setup port B pins into inputs
        mov     W0,LATB            
;
;		port C -- unused -- all outputs at 0
;
        clr     LATC
        clr     TRISC               
;
;		port D -- just the sync input -- INT1
;
        clr		LATD
        mov     #0b01,W0        	; setup port D pins into inputs
        mov     W0,TRISD
;
;		port E -- the control lines for SPI to the DAC's
;
        mov     #0b100111000,W0     ; most pins active low so drive high initially
        mov     W0,LATE            
        mov     #0b000000000,W0     ; setup port E pins into outputs
        mov     W0,TRISE            
;
;		port F -- the SPI peripheral pins
;
        mov     #0b0000,W0       	; setup port F pins into outputs
        mov     W0,TRISF            
;
;		configure the SPI module -- 16 bit transfer, interrupts
;
		mov		#0b0000000000000000,W0
		mov		W0,SPI1STAT
		mov		#0b0000011100111011,W0
		mov		W0,SPI1CON
		mov		#handle(SPIState1),W14
		bset	SPI1STAT,#SPIEN		; enable the SPI
        bclr    IFS0,#SPI1IF
        bset    IEC0,#SPI1IE
;
		mov		#0,W12
;
        mov     #psvpage(ftab),W1	; need this every time?
        mov     W1,PSVPAG
		bset	CORCON,#PSV
;
		mov		#2222,W0			; value from ADC!
		lsr		W0,#5,W1			; work out the step into the table / 32
		sl		W1,#2,W1			; x number of bytes per entry
		mov		#psvoffset(stab),W2
		add		W2,W1,W1			; now index into the table
		and		W0,#0b11111,W0		; mask off the bottom 5 bits
		mul.ss	W0,[W1++],W2		; multiply by scaling value
		asr		W2,#5,W2			; scaling back to adjust for rounding
		add		W2,[W1],W0
;
		mov		#121,W0				; value from ADC!
		lsr		W0,#5,W1			; work out the step into the table / 32
		sl		W1,#3,W1			; x number of bytes per entry
		mov		#psvoffset(ftab),W2
		add		W2,W1,W1			; now index into the table
		and		W0,#0b11111,W0		; mask off the bottom 5 bits
		mov.w	[W1++],W2			; get 32 bit scaling value from the table
		mov.w	[W1++],W3
		mul.uu	W0,W2,W4			; 
		mov.w	[W1++],W2			; get 32 bit offset value from the table
		mov.w	[W1++],W3
		sub		W2,W4,W4
		subb	W3,W5,W5
;
        bset    IFS0,#SPI1IF		; force interrupt to kick off! -- could also write to register!
;
hang:	btg		LATE,#1				; keep toggling test bit...
		bra		hang
;
;------------------------------------------------------------------------------
;
;		Random number generator -- copied from: http://www.firstpr.com.au/dsp/rand31/
;
rand31:
		mov		#16807,W0
		mov		#randval+2,W12
		mul.uu	W0,[W12--],W2
		mul.uu  W0,[W12],W0
		sl		W2,W2
		rlc		W3,W3
		lsr		W2,W2
		addc	W0,W3,W0
		addc	W2,W1,W1
		bra		n,rand31c
		mov		W1,randval+2
		mov		W0,randval
		return
;
rand31c:
		bclr	W1,#15
		inc		W0,W0
		addc	#0,W1
		mov		W1,randval+2
		mov		W0,randval
		return
;
;------------------------------------------------------------------------------
;
;		Frequency lookup table -- maps the voltage to the step in the w value
;
		.section *,psv
;
ftab:
	 .long   72459,42939893
     .long   68551,40623615
     .long   64853,38432282
     .long   61355,36359155
     .long   58045,34397857
     .long   54914,32542356
     .long   51952,30786945
     .long   49149,29126225
     .long   46498,27555089
     .long   43990,26068703
     .long   41617,24662496
     .long   39372,23332143
     .long   37248,22073553
     .long   35239,20882854
     .long   33338,19756384
     .long   31540,18690678
     .long   29838,17682459
     .long   28229,16728626
     .long   26706,15826245
     .long   25266,14972540
     .long   23903,14164886
     .long   22613,13400799
     .long   21393,12677929
     .long   20239,11994052
     .long   19148,11347064
     .long   18115,10734977
     .long   17138,10155907
     .long   16213,9608074
     .long   15339,9089792
     .long   14511,8599467
     .long   13728,8135592
     .long   12988,7696739
     .long   12287,7281559
     .long   11625,6888775
     .long   10997,6517178
     .long   10404,6165626
     .long   9843,5833038
     .long   9312,5518390
     .long   8810,5220715
     .long   8335,4939098
     .long   7885,4672671
     .long   7460,4420616
     .long   7057,4182158
     .long   6677,3956563
     .long   6316,3743136
     .long   5976,3541223
     .long   5653,3350201
     .long   5348,3169483
     .long   5060,2998514
     .long   4787,2836767
     .long   4529,2683745
     .long   4284,2538978
     .long   4053,2402019
     .long   3835,2272449
     .long   3628,2149868
     .long   3432,2033899
     .long   3247,1924185
     .long   3072,1820390
     .long   2906,1722194
     .long   2749,1629295
     .long   2601,1541407
     .long   2461,1458260
     .long   2328,1379598
     .long   2202,1305179
     .long   2084,1234775
     .long   1971,1168168
     .long   1865,1105154
     .long   1764,1045540
     .long   1669,989141
     .long   1579,935784
     .long   1494,885306
     .long   1413,837551
     .long   1337,792371
     .long   1265,749629
     .long   1197,709192
     .long   1132,670937
     .long   1071,634745
     .long   1013,600505
     .long   959,568112
     .long   907,537467
     .long   858,508475
     .long   812,481047
     .long   768,455098
     .long   727,430549
     .long   687,407324
     .long   650,385352
     .long   615,364565
     .long   582,344900
     .long   551,326295
     .long   521,308694
     .long   493,292042
     .long   466,276289
     .long   441,261385
     .long   417,247285
     .long   395,233946
     .long   373,221327
     .long   353,209388
     .long   334,198093
     .long   316,187407
     .long   299,177298
     .long   283,167734
     .long   268,158686
     .long   253,150126
     .long   240,142028
     .long   227,134367
     .long   215,127119
     .long   203,120262
     .long   192,113774
     .long   182,107637
     .long   172,101831
     .long   163,96338
     .long   154,91141
     .long   146,86225
     .long   138,81574
     .long   130,77173
     .long   123,73011
     .long   117,69072
     .long   110,65346
     .long   104,61821
     .long   99,58487
     .long   93,55332
     .long   88,52347
     .long   84,49523
     .long   79,46852
     .long   75,44325
     .long   71,41934
     .long   67,39672
     .long   63,37532
;
stab:
     .short   100,2048 ; 3.1382,2047.55
     .short   100,2148 ; 3.13453,2147.98
     .short   100,2248 ; 3.11822,2248.2
     .short   99,2348 ; 3.10026,2347.91
     .short   98,2447 ; 3.07313,2446.9
     .short   97,2545 ; 3.04527,2544.89
     .short   95,2642 ; 2.97526,2642.23
     .short   94,2737 ; 2.93273,2737.39
     .short   92,2831 ; 2.86895,2831.25
     .short   90,2923 ; 2.80352,2923.11
     .short   87,3013 ; 2.72874,3012.95
     .short   85,3100 ; 2.65011,3100.45
     .short   82,3185 ; 2.57221,3185.19
     .short   79,3267 ; 2.48039,3267.4
     .short   76,3347 ; 2.37848,3346.66
     .short   73,3423 ; 2.27621,3422.75
     .short   69,3496 ; 2.15854,3495.7
     .short   65,3565 ; 2.04032,3565.06
     .short   62,3630 ; 1.93787,3630.43
     .short   58,3692 ; 1.80425,3692.47
     .short   54,3750 ; 1.68109,3750.26
     .short   50,3804 ; 1.54985,3804.04
     .short   45,3854 ; 1.41532,3853.56
     .short   41,3899 ; 1.28098,3898.68
     .short   36,3940 ; 1.1327,3939.51
     .short   31,3976 ; 0.980205,3975.87
     .short   27,4007 ; 0.83816,4007.23
     .short   22,4034 ; 0.691532,4034
     .short   17,4056 ; 0.529509,4056.07
     .short   12,4073 ; 0.390029,4073.2
     .short   8,4085 ; 0.23662,4085.43
     .short   3,4093 ; 0.0813783,4092.93
     .short   -2,4095 ; -0.0788123,4095.47
     .short   -6,4093 ; -0.234054,4092.97
     .short   -11,4086 ; -0.384897,4085.59
     .short   -16,4073 ; -0.528959,4073.01
     .short   -21,4056 ; -0.690799,4056.11
     .short   -26,4034 ; -0.83651,4034.03
     .short   -30,4007 ; -0.973607,4007.15
     .short   -35,3976 ; -1.12537,3975.63
     .short   -40,3940 ; -1.27309,3939.55
     .short   -44,3899 ; -1.40707,3898.72
     .short   -48,3854 ; -1.546,3853.56
     .short   -53,3804 ; -1.67925,3804.03
     .short   -57,3750 ; -1.80022,3750.15
     .short   -61,3692 ; -1.93273,3692.36
     .short   -64,3630 ; -2.03794,3630.31
     .short   -68,3565 ; -2.15561,3564.76
     .short   -72,3496 ; -2.27438,3495.53
     .short   -75,3423 ; -2.37573,3422.76
     .short   -78,3347 ; -2.47361,3346.65
     .short   -81,3267 ; -2.56818,3267.43
     .short   -84,3185 ; -2.64589,3185.2
     .short   -86,3100 ; -2.72746,3100.24
     .short   -89,3013 ; -2.80389,3012.84
     .short   -91,2923 ; -2.86712,2923.03
     .short   -93,2831 ; -2.92907,2831.18
     .short   -94,2737 ; -2.97141,2737.37
     .short   -96,2642 ; -3.04399,2642.31
     .short   -97,2545 ; -3.0724,2545.22
     .short   -98,2447 ; -3.10007,2447.11
     .short   -99,2348 ; -3.11712,2347.97
     .short   -99,2248 ; -3.13306,2248.25
     .short   -100,2148 ; -3.14113,2148
     .short   -99,2047 ; -3.1382,2047.45
     .short   -99,1947 ; -3.13453,1947.02
     .short   -99,1847 ; -3.11822,1846.8
     .short   -98,1747 ; -3.10026,1747.09
     .short   -97,1648 ; -3.07313,1648.1
     .short   -96,1550 ; -3.04527,1550.11
     .short   -94,1453 ; -2.97526,1452.77
     .short   -93,1358 ; -2.93273,1357.61
     .short   -91,1264 ; -2.86895,1263.75
     .short   -89,1172 ; -2.80352,1171.89
     .short   -86,1082 ; -2.72874,1082.05
     .short   -84,995 ; -2.65011,994.545
     .short   -81,910 ; -2.57221,909.807
     .short   -78,828 ; -2.48039,827.602
     .short   -75,748 ; -2.37848,748.335
     .short   -72,672 ; -2.27621,672.25
     .short   -68,599 ; -2.15854,599.301
     .short   -64,530 ; -2.04032,529.938
     .short   -61,465 ; -1.93787,464.568
     .short   -57,403 ; -1.80425,402.528
     .short   -53,345 ; -1.68109,344.744
     .short   -49,291 ; -1.54985,290.96
     .short   -44,241 ; -1.41532,241.438
     .short   -40,196 ; -1.28098,196.324
     .short   -35,155 ; -1.1327,155.494
     .short   -30,119 ; -0.980205,119.131
     .short   -26,88 ; -0.83816,87.7727
     .short   -21,61 ; -0.691532,61
     .short   -16,39 ; -0.529509,38.9261
     .short   -11,22 ; -0.390029,21.7955
     .short   -7,10 ; -0.23662,9.57386
     .short   -2,2 ; -0.0813783,2.07386
     .short   3,0 ; 0.0788123,-0.471591
     .short   7,2 ; 0.234054,2.02841
     .short   12,9 ; 0.384897,9.40909
     .short   17,22 ; 0.528959,21.9886
     .short   22,39 ; 0.690799,38.8864
     .short   27,61 ; 0.83651,60.9716
     .short   31,88 ; 0.973607,87.8466
     .short   36,119 ; 1.12537,119.369
     .short   41,155 ; 1.27309,155.455
     .short   45,196 ; 1.40707,196.284
     .short   49,241 ; 1.546,241.443
     .short   54,291 ; 1.67925,290.972
     .short   58,345 ; 1.80022,344.847
     .short   62,403 ; 1.93273,402.636
     .short   65,465 ; 2.03794,464.693
     .short   69,530 ; 2.15561,530.244
     .short   73,599 ; 2.27438,599.466
     .short   76,672 ; 2.37573,672.239
     .short   79,748 ; 2.47361,748.347
     .short   82,828 ; 2.56818,827.568
     .short   85,910 ; 2.64589,909.801
     .short   87,995 ; 2.72746,994.756
     .short   90,1082 ; 2.80389,1082.16
     .short   92,1172 ; 2.86712,1171.97
     .short   94,1264 ; 2.92907,1263.82
     .short   95,1358 ; 2.97141,1357.63
     .short   97,1453 ; 3.04399,1452.69
     .short   98,1550 ; 3.0724,1549.78
     .short   99,1648 ; 3.10007,1647.89
     .short   100,1747 ; 3.11712,1747.03
     .short   100,1847 ; 3.13306,1846.75
     .short   101,1947 ; 3.14113,1947
;
;------------------------------------------------------------------------------
;
        .end
